#import "ALWrappingTextElementColumnEntry.h"
#import "SMRSubtleScrollView.h"
#import "SMRSubtleResizeControl.h"
#import "NSManagedObject+SMRAdditions.h"
#import "NSObject+BlockObservation.h"

#pragma mark Constants
static const NSUInteger ALWrappingTextViewMinimumLineCount = 4;


#pragma mark -
@interface ALWrappingTextElementColumnEntry ()
@property (nonatomic, assign) CGFloat scrollViewVerticalPadding;
@property (nonatomic, assign) CGFloat scrollViewHorizontalPadding;
@end


#pragma mark -
@interface ALWrappingTextElementColumnEntry (ALWrappingTextElementColumnEntryPrivateMethods)
-(NSView *)findViewOfClass_:(Class)viewClass inSubviewsOfView:(NSView *)parentView;
-(CGFloat)persistentMaxTextViewHeight_;
-(void)setPersistentMaxTextViewHeight_:(CGFloat)maxHeight;
-(NSString *)persistentMaxTextViewHeightKey_;
-(CGFloat)textHeightForWidth_:(CGFloat)theWidth;
-(CGFloat)minimumTextViewHeight_;
@end


#pragma mark -
@implementation ALWrappingTextElementColumnEntry

@synthesize valueView;
@synthesize scrollView;
@synthesize scrollViewVerticalPadding;
@synthesize scrollViewHorizontalPadding;


-(void)awakeFromNib {
	NSRect viewFrame = [[self view] frame];
	NSRect scrollViewFrame = [[self scrollView] frame];
	[self setScrollViewVerticalPadding:viewFrame.size.height - scrollViewFrame.size.height];
	[self setScrollViewHorizontalPadding:viewFrame.size.width - scrollViewFrame.size.width];
	
	[[self valueView] setEditable:NO];
	[[self valueView] setFont:[NSFont systemFontOfSize:ALElementFontSizePrimary]];

	AMBlockTask fontSizeTask = ^(id object, NSDictionary *change) {
		// Adjust font size based on status as primary/secondary
		BOOL elementIsPrimary = [self elementIsPrimary];
		CGFloat currentFontSize = [[[self valueView] font] pointSize];
		CGFloat newFontSize = elementIsPrimary ? ALElementFontSizePrimary : ALElementFontSizeSecondary;
		[[self valueView] setFont:[NSFont systemFontOfSize:newFontSize]];
		
		// Adjust scrollView/textView height to align with label
		CGFloat fontSizeDelta = currentFontSize - newFontSize;
		CGFloat scrollVerticalPadding = [self scrollViewVerticalPadding];
		scrollVerticalPadding += fontSizeDelta;
		[self setScrollViewVerticalPadding:scrollVerticalPadding];
		
		NSRect scrollFrame = [[self scrollView] frame];
		scrollFrame.size.height -= fontSizeDelta;
		[[self scrollView] setFrame:scrollFrame];
		
		[self setNeedsLayout:YES];
	};
	NSString *lineNumberKey = [NSString stringWithFormat:@"%@.%@", ALRepresentedObjectKey, ALLineNumberKey];
	[self addObserverForKeyPath:lineNumberKey task:fontSizeTask];
	
	AMBlockTask selectedTask = ^(id object, NSDictionary *change) {
		[[self scrollView] setSelected:[[self parentEntry] selected]];
	};
	NSString *selectedKey = [NSString stringWithFormat:@"%@.%@", ALParentEntryKey, ALSelectedKey];
	[self addObserverForKeyPath:selectedKey task:selectedTask];
}


#pragma mark -
#pragma mark Text view delegate

-(void)textDidChange:(NSNotification *)aNotification {
	[[self columnView] layoutWithAnimation:NO];
}


#pragma mark -
#pragma mark Column entry overrides

-(void)columnEntryWasAddedToColumnView {
	[super columnEntryWasAddedToColumnView];
	[[self valueView] scrollRangeToVisible:NSMakeRange(0, 0)];
}

-(void)columnEntryWasRemovedFromColumnView:(SMRColumnView *)aColumnView {
	[super columnEntryWasRemovedFromColumnView:aColumnView];
	[[NSUserDefaults standardUserDefaults] removeObjectForKey:[self persistentMaxTextViewHeightKey_]];
}

-(void)columnEntryDidBeginEditingAtPoint:(NSPoint)clickPoint {
	[super columnEntryDidBeginEditingAtPoint:clickPoint];
	[[self valueView] setEditable:YES];
}

-(void)columnEntryDidEndEditing {
	[super columnEntryDidEndEditing];
	[[self valueView] setEditable:NO];
	[[self valueView] setSelectedRange:NSMakeRange(0, 0)];
}

-(CGFloat)preferredHeightForWidth:(CGFloat)theWidth {
	NSScroller *verticalScroller = [[self scrollView] verticalScroller];
	CGFloat scrollerWidth = [[verticalScroller class] scrollerWidth];
	CGFloat scrollViewWidth = theWidth - [self scrollViewHorizontalPadding] - scrollerWidth;

	CGFloat textHeight = [self textHeightForWidth_:scrollViewWidth];
	CGFloat maxTextViewHeight = [self persistentMaxTextViewHeight_];
	CGFloat preferredHeight = fmin(textHeight, maxTextViewHeight);
	preferredHeight += [self scrollViewVerticalPadding];
//	NSLog(@"text %f   maxText %f  preferred %f", textHeight, maxTextViewHeight, preferredHeight);
	return preferredHeight;
}

-(NSView *)willForwardHitTestAtPoint:(NSPoint)aPoint toSubview:(NSView *)subview {
	NSEventType currentEventType = [[NSApp currentEvent] type];
	BOOL isScrollWheel = currentEventType == NSScrollWheel;
	
	if (subview == [self valueView]) 
		return (isScrollWheel || [[self valueView] isEditable]) ? subview : [self columnView];
	if (subview == [[self scrollView] verticalScroller])
		return subview;
	if (subview == [[self scrollView] resizeControl])
		return isScrollWheel ? [self valueView] : subview;
	return [self columnView];
}


#pragma mark -
#pragma mark Subtle scroll view delegate

-(CGFloat)maximumResizeHeightOfScrollView:(SMRSubtleScrollView *)aScrollView {
	CGFloat textViewWidth = [[self valueView] frame].size.width;
	CGFloat textHeight = [self textHeightForWidth_:textViewWidth];
	return textHeight + [self scrollViewVerticalPadding];
}

-(CGFloat)minimumResizeHeightOfScrollView:(SMRSubtleScrollView *)aScrollView {
	return [self minimumTextViewHeight_] + [self scrollViewVerticalPadding];
}

-(NSView *)substituteResizeViewForScrollView:(SMRSubtleScrollView *)aScrollView {
	return [self view];
}

-(void)scrollView:(SMRSubtleScrollView *)aScrollView resizeView:(NSView *)substituteView withRect:(NSRect)aRect {
	[self setPersistentMaxTextViewHeight_:(aRect.size.height - [self scrollViewVerticalPadding])];
	[[self columnView] layoutWithAnimation:NO];
}

-(BOOL)shouldHideResizeViewForScrollView:(SMRSubtleScrollView *)aScrollView {
	CGFloat textViewWidth = [[self valueView] frame].size.width;
	CGFloat textHeight = [self textHeightForWidth_:textViewWidth];
	if (textHeight <= [self minimumTextViewHeight_])
		return YES;
	return NO;
}


#pragma mark -
#pragma mark Private

-(CGFloat)minimumTextViewHeight_ {
	CGFloat lineHeight = [[[self valueView] layoutManager] defaultLineHeightForFont:[[self valueView] font]];
	CGFloat minimumTextViewHeight = lineHeight * ALWrappingTextViewMinimumLineCount;
	return minimumTextViewHeight;
}

-(CGFloat)textHeightForWidth_:(CGFloat)theWidth {
	NSTextView *textView = [self valueView];
//	NSLayoutManager *valueViewLayoutManager = [textView layoutManager];
	NSTextContainer *valueViewTextContainer = [textView textContainer];
//	CGFloat insetHeight = [textView textContainerInset].height;
//	[valueViewLayoutManager glyphRangeForTextContainer:valueViewTextContainer];
//	CGFloat valueViewTextHeight = [valueViewLayoutManager usedRectForTextContainer:valueViewTextContainer].size.height;
//	CGFloat valueViewCalculatedTextHeight = (2 * insetHeight) + valueViewTextHeight;

	NSString *currentString = [textView string];
	NSFont *currentFont = [[self valueView] font];
	NSTextStorage *textStorage = [[[NSTextStorage alloc] initWithString:currentString] autorelease];
	NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize: NSMakeSize(theWidth, FLT_MAX)];
	NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
	[layoutManager addTextContainer:textContainer];
	[textStorage addLayoutManager:layoutManager];
	[textStorage addAttribute:NSFontAttributeName value:currentFont range:NSMakeRange(0, [textStorage length])];
	[textContainer setLineFragmentPadding:[valueViewTextContainer lineFragmentPadding]];
	[layoutManager glyphRangeForTextContainer:textContainer];
	CGFloat constructedCalculatedTextHeight = [layoutManager usedRectForTextContainer:textContainer].size.height;
	CGFloat lineHeight = [layoutManager defaultLineHeightForFont:currentFont];
	return fmax(constructedCalculatedTextHeight, lineHeight);
}

-(CGFloat)persistentMaxTextViewHeight_ {
	CGFloat maxHeight = [[NSUserDefaults standardUserDefaults] floatForKey:[self persistentMaxTextViewHeightKey_]];
	if (maxHeight == 0) 
		maxHeight = [self minimumTextViewHeight_];
	return maxHeight;
}

-(void)setPersistentMaxTextViewHeight_:(CGFloat)viewHeight {
	if (viewHeight < [self minimumTextViewHeight_])
		return;
	[[NSUserDefaults standardUserDefaults] setFloat:viewHeight forKey:[self persistentMaxTextViewHeightKey_]];
}

-(NSString *)persistentMaxTextViewHeightKey_ {
	return [NSString stringWithFormat:@"%@.persistentTextViewHeight", [[self representedObject] smrURIRepresentation]];
}

@end
